#include <stdbool.h>
#include <stdlib.h>
#include "clib_container_vector.h"


#define DEFAULT_CAPACITY 8
#define DEFAULT_EXPANSION_FACTOR 2

#define MAX_ELEMENTS ((size_t) - 2)

struct clib_container_vector {
    size_t current_size;
    size_t capacity;
    float exp_factor;
    void **buffer;

    void *(*mem_malloc_func)(size_t size);

    void (*mem_free_func)(void *block);

    void *(*mem_copy_func)(void *target,const void *src, size_t size);
};


int clib_container_vector_create_with_conf(struct clib_container_vector_conf *conf,
                                           struct clib_container_vector **out) {
    clib_check_if_true_return_value(conf == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(conf->mem_copy_func == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(conf->mem_malloc_func == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(conf->mem_free_func == NULL, CLIB_RES_PARAM_ERROR);

    if (conf->capacity == 0) {
        conf->capacity = DEFAULT_CAPACITY;
    }

    float ex = DEFAULT_EXPANSION_FACTOR;
    //分配内存
    struct clib_container_vector *vector = conf->mem_malloc_func(sizeof(struct clib_container_vector));
    if (!vector) {
        return CLIB_RES_MEMORY_ERROR;
    }
    //分配存储数据的数组指针内存
    void **buff = conf->mem_malloc_func(conf->capacity * sizeof(void *));
    if (!buff) {
        conf->mem_free_func(vector);
        return CLIB_RES_MEMORY_ERROR;
    }
    vector->buffer = buff;
    vector->exp_factor = ex;
    vector->capacity = conf->capacity;
    vector->mem_malloc_func = conf->mem_malloc_func;
    vector->mem_free_func = conf->mem_free_func;
    vector->mem_copy_func = conf->mem_copy_func;
    *out = vector;
    return CLIB_RES_OK;
}


void clib_container_vector_destroy(struct clib_container_vector *vector) {
    vector->mem_free_func(vector->buffer);
    vector->mem_free_func(vector);
}

static int expand_capacity(struct clib_container_vector *vector) {
    if (vector->capacity == MAX_ELEMENTS) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }
    //计算扩容后的容量
    size_t new_capacity = vector->capacity * vector->exp_factor;
    if (new_capacity <= vector->capacity) {
        vector->capacity = MAX_ELEMENTS;
    } else {
        vector->capacity = new_capacity;
    }
    //分配新的数组
    void **new_buff = vector->mem_malloc_func(new_capacity * sizeof(void *));
    if (!new_buff) {
        return CLIB_RES_MEMORY_ERROR;
    }
    //拷贝数据
    vector->mem_copy_func(new_buff, vector->buffer, vector->current_size * sizeof(void *));
    //释放原来的数据
    vector->mem_free_func(vector->buffer);
    //切换为新的数组
    vector->buffer = new_buff;
    return CLIB_RES_OK;
}

int clib_container_vector_add(struct clib_container_vector *vector, void *element) {
    if (vector->current_size >= vector->capacity) {
        int status = expand_capacity(vector);
        if (status != CLIB_RES_OK) {
            return status;
        }
    }
    vector->buffer[vector->current_size] = element;
    vector->current_size++;
    return CLIB_RES_OK;
}

int clib_container_vector_add_with_index(struct clib_container_vector *vector, void *element, size_t index) {
    if (index == vector->current_size) {
        return clib_container_vector_add(vector, element);
    }
    if ((vector->current_size == 0 && index != 0) || index > (vector->current_size - 1)) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }
    if (vector->current_size >= vector->capacity) {
        int status = expand_capacity(vector);
        if (status != CLIB_RES_OK) {
            return status;
        }
    }
    //计算需要偏移的量
    size_t shift = (vector->current_size - index) * sizeof(void *);
    //偏移数据
    memmove(&(vector->buffer[index + 1]),
            &(vector->buffer[index]),
            shift);
    //赋值
    vector->buffer[index] = element;
    vector->current_size++;
    return CLIB_RES_OK;
}

int clib_container_vector_replace_with_index(struct clib_container_vector *vector, void *element, size_t index,
                                             void **out) {
    if (index >= vector->current_size) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }
    if (out) {
        //将原来的值返回
        *out = vector->buffer[index];
    }
    vector->buffer[index] = element;
    return CLIB_RES_OK;
}


int clib_container_vector_swap_with_index(struct clib_container_vector *vector, size_t index1, size_t index2) {
    void *tmp;
    if (index1 >= vector->current_size || index2 >= vector->current_size) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }
    tmp = vector->buffer[index1];
    vector->buffer[index1] = vector->buffer[index2];
    vector->buffer[index2] = tmp;
    return CLIB_RES_OK;
}


int clib_container_vector_index_of(struct clib_container_vector *vector, void *element, size_t *index) {
    size_t i;
    for (i = 0; i < vector->current_size; i++) {
        if (vector->buffer[i] == element) {
            *index = i;
            return CLIB_RES_OK;
        }
    }
    return CLIB_RES_OUT_OF_BOUNDS_ERROR;
}

int clib_container_vector_remove(struct clib_container_vector *vector, void *element) {
    size_t index;
    int status = clib_container_vector_index_of(vector, element, &index);

    if (status != CLIB_RES_OK) {
        return status;
    }
    if (index != vector->current_size - 1) {
        size_t block_size = (vector->current_size - 1 - index) * sizeof(void *);
        memmove(&(vector->buffer[index]),
                &(vector->buffer[index + 1]),
                block_size);
    }
    vector->current_size--;
    return CLIB_RES_OK;
}

int clib_container_vector_remove_with_index(struct clib_container_vector *vector, size_t index, void **out) {
    if (index >= vector->current_size) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }

    if (out != NULL) {
        *out = vector->buffer[index];
    }

    if (index != vector->current_size - 1) {
        size_t block_size = (vector->current_size - 1 - index) * sizeof(void *);
        memmove(&(vector->buffer[index]),
                &(vector->buffer[index + 1]),
                block_size);
    }
    vector->current_size--;
    return CLIB_RES_OK;
}


int clib_container_vector_remove_last(struct clib_container_vector *vector, void **out) {
    return clib_container_vector_remove_with_index(vector, vector->current_size - 1, out);
}


int clib_container_vector_get_with_index(struct clib_container_vector *vector, size_t index, void **out) {
    if (index >= vector->current_size) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }
    *out = vector->buffer[index];
    return CLIB_RES_OK;
}


int clib_container_vector_get_last(struct clib_container_vector *vector, void **out) {
    if (vector->current_size == 0) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }
    return clib_container_vector_get_with_index(vector, vector->current_size - 1, out);
}

int clib_container_vector_create_sub(struct clib_container_vector *vector, size_t begin_index, size_t end_index,
                                     struct clib_container_vector **out) {
    if (begin_index > end_index || end_index >= vector->current_size) {
        return CLIB_RES_PARAM_ERROR;
    }
    struct clib_container_vector *sub_vector = vector->mem_malloc_func(sizeof(struct clib_container_vector));
    if (!sub_vector) {
        return CLIB_RES_MEMORY_ERROR;
    }
    if (!(sub_vector->buffer = vector->mem_malloc_func(vector->capacity * sizeof(void *)))) {
        vector->mem_free_func(sub_vector);
        return CLIB_RES_MEMORY_ERROR;
    }
    sub_vector->mem_malloc_func = vector->mem_malloc_func;
    sub_vector->mem_free_func = vector->mem_free_func;
    sub_vector->mem_copy_func = vector->mem_copy_func;
    sub_vector->current_size = end_index - begin_index + 1;
    sub_vector->capacity = sub_vector->current_size;
    //拷贝数据
    vector->mem_copy_func(sub_vector->buffer,
                          &(vector->buffer[begin_index]),
                          sub_vector->current_size * sizeof(void *));
    *out = sub_vector;
    return CLIB_RES_OK;
}


int clib_container_vector_filter(struct clib_container_vector *vector,
                                 bool (*filter)(const void *),
                                 void **out) {
    if (vector->current_size == 0) {
        return CLIB_RES_OUT_OF_BOUNDS_ERROR;
    }
    int rm_index = 0;
    size_t rm = 0;
    size_t keep = 0;
    for (size_t i = vector->current_size - 1; i != ((size_t) -1); i--) {
        if (!filter(vector->buffer[i])) {
            rm++;
            if (out != NULL) {
                out[rm_index] = vector->buffer[i];
            }
            rm_index += 1;
            continue;
        }
        if (rm > 0) {
            if (keep > 0) {
                size_t block_size = keep * sizeof(void *);
                memmove(&(vector->buffer[i + 1]),
                        &(vector->buffer[i + 1 + rm]),
                        block_size);
            }
            vector->current_size -= rm;
            rm = 0;
        }
        keep++;
    }
    if (rm > 0) {
        size_t block_size = keep * sizeof(void *);
        memmove(&(vector->buffer[0]),
                &(vector->buffer[rm]),
                block_size);

        vector->current_size -= rm;
    }
    return CLIB_RES_OK;
}


void clib_container_vector_reverse(struct clib_container_vector *vector) {
    if (vector->current_size == 0)
        return;

    size_t i;
    size_t j;
    for (i = 0, j = vector->current_size - 1; i < (vector->current_size - 1) / 2; i++, j--) {
        void *tmp = vector->buffer[i];
        vector->buffer[i] = vector->buffer[j];
        vector->buffer[j] = tmp;
    }
}


int clib_container_vector_trim_capacity(struct clib_container_vector *vector) {
    if (vector->current_size == vector->capacity) {
        return CLIB_RES_OK;
    }
    void **new_buff = vector->mem_malloc_func(vector->current_size * sizeof(void *));
    if (!new_buff) {
        return CLIB_RES_MEMORY_ERROR;
    }
    size_t size = vector->current_size < 1 ? 1 : vector->current_size;
    vector->mem_copy_func(new_buff, vector->buffer, size * sizeof(void *));
    vector->mem_free_func(vector->buffer);
    vector->buffer = new_buff;
    vector->capacity = vector->current_size;
    return CLIB_RES_OK;
}


size_t clib_container_vector_contains(struct clib_container_vector *vector, void *element) {
    size_t o = 0;
    size_t i;
    for (i = 0; i < vector->current_size; i++) {
        if (vector->buffer[i] == element) {
            o++;
        }
    }
    return o;
}

size_t clib_container_vector_get_current_size(struct clib_container_vector *vector) {
    return vector->current_size;
}

size_t clib_container_vector_get_capacity(struct clib_container_vector *vector) {
    return vector->capacity;
}

void clib_container_vector_sort(struct clib_container_vector *vector, int (*compare)(const void *, const void *)) {
    qsort(vector->buffer, vector->current_size, sizeof(void *), compare);
}

void clib_container_vector_map(struct clib_container_vector *vector, void (*map)(void *e)) {
    size_t i;
    for (i = 0; i < vector->current_size; i++) {
        map(vector->buffer[i]);
    }
}

void clib_container_vector_reduce(struct clib_container_vector *vector, void (*reduce)(void *, void *, void *),
                                  void *result) {
    if (vector->current_size == 1) {
        reduce(vector->buffer[0], NULL, result);
        return;
    }
    if (vector->current_size > 1) {
        reduce(vector->buffer[0], vector->buffer[1], result);
    }
    for (size_t i = 2; i < vector->current_size; i++) {
        reduce(result, vector->buffer[i], result);
    }
}




